from Products.Archetypes.interfaces import IBaseObject

from Acquisition import aq_inner
from Acquisition import aq_parent

from plone.app.multilingual.interfaces import *
from plone.app.multilingual import events

from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.utils import _createObjectByType
from persistent.interfaces import IPersistent
from zope.component import adapts
from zope.interface import implements
from zope.event import notify



class TranslateSchema(object):
    pass

#
# Policy translation functions
# 

class TranslatableStringElement(object):
    """ To translate a string
    """
    implements(ITranslatableElement)

    text = ''
    language = ''

    def __init__(self, context, language):
        self.text = context
        self.language = language
        

class TranslationServiceGoogle(object):
    """ Define a webservice where we send the actual text to translate
    """
    implements(ITranslationService)
    adapts(ITranslatableElement)

    name = "Google Translate"
    _url = "http://translate.google.com/translate_t"
    _method = "post"

    def __init__(self, context):
        self._text = context.text

    def getTranslation(self,  tolanguage):
        # XXX : TODO
        pass

	
	

class LocateTranslation(object):
        """Default ILocateTranslation adapter.

        If the parent for an object is translatable and has a translation
        to the desired language that translation will be used as the new
        location. In all other cases the new translation will be put in
        the same location as the current object.
        """
        implements(ILocateTranslation)
        adapts(ITranslatable)

        def __init__(self, context):
            self.context=context


        def findLocationForTranslation(self, language):
            """ Look the policy that has been choosen if it's RootLang return none in case 
            the parent is not translated
            """
            ptool = getToolByName(context, "portal_properties").multilingual_properties
            parent = aq_parent(aq_inner(self.context))

            if ptool.storage_rootlang:
                location = None
            else:
                location = parent
                
            try:    
                trans_parent = ITranslationGroupLookup(parent, None)
            except NotTranslatable:
                return location
                
            if trans_parent is None:
                return location

            return trans_parent.getTranslation(language) or location
	

def finishTranslation(context, event):
            # Check if policy is default
            ptool = getToolByName(context, "portal_properties").multilingual_properties
            if ptool.storage_rootlang:
                return
            
            # If this is a folder, move translated subobjects aswell.
            if context.isPrincipiaFolderish:
                moveids = []
                for obj in context.objectValues():
                    translator = ITranslatable(obj, None)
                    if translator is not None and translator.getLanguage() == language:
                        lockable = ILockable(obj, None)
                        if lockable is not None and lockable.can_safely_unlock():
                            lockable.unlock()
                        moveids.append(obj.getId())
                if moveids:
                    info = context.manage_cutObjects(moveids)
                    translation.manage_pasteObjects(info)


#
# Basic translate functions
# 
	
class TranslationFactory(object):
    """Default translation factory.
    """

    implements(ITranslationFactory)
    adapts(ITranslatable)

    def __init__(self, context):
        self.context=context


    def generateId(self, container, canonical_id, language):
        new_id = canonical_id
        suffix = "-" + str(language)    # unicode breaks `checkValidId()`
        while not container.checkIdAvailable(new_id):
            new_id += suffix

        return new_id


    def getTranslationPortalType(self, container, language):
        return self.context.portal_type


    def createTranslation(self, container, language, *args, **kwargs):
        context = aq_inner(self.context)
        portal_type = self.getTranslationPortalType(container, language)
        new_id = self.generateId(container, self.context.getId(), language)
        kwargs["language"] = language
        translation = _createObjectByType(portal_type, container,
                                          new_id, *args, **kwargs)

        # Copy language independent fields
        ILanguageIndependentFields(self.context).copyFields(translation)
        
        # Try to translate non language independent fields
        ptool = getToolByName(context, "portal_properties").multilingual_properties
        if ptool.trytotranslate:
            ILanguageDependentFields(self.context).copyFields(translation)
        
        return translation
	

class LanguageDependentFields(object):
    """Default language dependent field manager.
    """
    implements(ILanguageDependentFields)
    adapts(ITranslatable)
    

    # TODO: try automatic tanslate
    # To translate somethign TranslatableStringElement(string)
    # ITranslationService(TranslatableStringElement(string)).getTranslation
    def __init__(self, context):
        self.context = context


    def getFields(self, schema=None):
        if schema is None:
            schema = self.context.Schema()
        return schema.filterFields(languageIndependent=True)


    def getFieldsToCopy(self, translation, source_schema=None, dest_schema=None):
        # Only copy fields that exist in the destination schema.
        if source_schema is None:
            source_schema = self.context.Schema()
        if dest_schema is None:
            dest_schema = translation.Schema()
        fields = self.getFields(source_schema)
        return [x for x in fields if x.getName() in dest_schema]


    def copyField(self, field, translation):
        accessor = field.getEditAccessor(self.context)
        if not accessor:
            accessor = field.getAccessor(self.context)
        data = accessor()
        mutatorname = getattr(field, 'translation_mutator', None)
        if mutatorname is None:
            # We have a field from archetypes.schemaextender or something
            # else not using ClassGen. Fall back to default mutator.
            translation.getField(field.getName()).set(translation, data)
        else:
            # Holy ClassGen crap - we have a generated method!
            translation_mutator = getattr(translation, mutatorname)
            translation_mutator(data)


    def copyFields(self, translation):
        for field in self.getFieldsToCopy(translation):
            self.copyField(field, translation)

    


class LanguageIndependentFields(object):
    """Default language independent fields manager.
    """

    implements(ILanguageIndependentFields)
    adapts(ITranslatable)


    # TODO: try automatic tanslate
    # To translate somethign TranslatableStringElement(string)
    # ITranslationService(TranslatableStringElement(string)).getTranslation
    def __init__(self, context):
        self.context = context


    def getFields(self, schema=None):
        if schema is None:
            schema = self.context.Schema()
        return schema.filterFields(languageIndependent=True)


    def getFieldsToCopy(self, translation, source_schema=None, dest_schema=None):
        # Only copy fields that exist in the destination schema.
        if source_schema is None:
            source_schema = self.context.Schema()
        if dest_schema is None:
            dest_schema = translation.Schema()
        fields = self.getFields(source_schema)
        return [x for x in fields if x.getName() in dest_schema]


    def copyField(self, field, translation):
        accessor = field.getEditAccessor(self.context)
        if not accessor:
            accessor = field.getAccessor(self.context)
        data = accessor()
        mutatorname = getattr(field, 'translation_mutator', None)
        if mutatorname is None:
            # We have a field from archetypes.schemaextender or something
            # else not using ClassGen. Fall back to default mutator.
            translation.getField(field.getName()).set(translation, data)
        else:
            # Holy ClassGen crap - we have a generated method!
            translation_mutator = getattr(translation, mutatorname)
            translation_mutator(data)


    def copyFields(self, translation):
        for field in self.getFieldsToCopy(translation):
            self.copyField(field, translation)


	
class Translate(object):
    """ Lets translate an object !!
    """
    implements(ITranslate)
    adapts(ITranslatable)

    def __init__(self, context):
        self.origin = context

    def translate(self, language, auto=False, *args, **kwargs):
        """ Method to translate an object, it delegates to different interfaces the location where is translated
            and how to translate the object.
            language : language target to translate
            self.origin : original object to translate
        """
        translationgroup = ITranslationGroupLookup(self.origin)
        if translationgroup.hasTranslation(language):
            translation = self.getTranslation(language)
            raise AlreadyTranslated, translation.absolute_url()

        locator = ILocateTranslation(self.origin)
        parent = locator.findLocationForTranslation(language)
        if not parent:
            raise CouldNotTranslate
            
        notify(events.ObjectWillBeTranslatedEvent(self.origin, language))

        factory = ITranslationFactory(self.origin)
        translation = factory.createTranslation(parent, language, *args, **kwargs)

        #TODO : self.origin.invalidateTranslationCache()        
        translation.reindexObject()
        notify(events.ObjectTranslatedEvent(self.origin, translation, language))

        return translation
    


    

